"""
Pydantic schemas for analysis result data validation and serialization.
"""

from datetime import datetime
from typing import Dict, Any, List, Optional, Union
from pydantic import BaseModel, Field, validator


class AnalysisResultSchema(BaseModel):
    """Schema for analysis result data."""
    
    id: Optional[str] = None
    call_tree_id: Optional[str] = Field(None, description="Associated call tree ID")
    
    # Analysis identification
    analysis_type: str = Field(description="Type of analysis performed")
    target_path: str = Field(description="File or directory path analyzed")
    language: Optional[str] = Field(None, description="Programming language")
    
    # Analysis results
    results: Dict[str, Any] = Field(description="Analysis results data")
    
    # Analysis metadata
    success: bool = Field(default=True, description="Whether analysis was successful")
    error_message: Optional[str] = Field(None, description="Error message if analysis failed")
    processing_time_ms: Optional[float] = Field(None, ge=0, description="Processing time in milliseconds")
    
    # Cache and invalidation
    cache_key: Optional[str] = Field(None, description="Cache key for this analysis")
    file_hash: Optional[str] = Field(None, description="Hash of analyzed file(s)")
    dependencies_hash: Optional[str] = Field(None, description="Hash of dependencies")
    
    # Timestamps
    created_at: Optional[datetime] = None
    expires_at: Optional[datetime] = Field(None, description="Cache expiration time")
    
    # Additional metadata
    metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
    
    class Config:
        """Pydantic configuration."""
        json_encoders = {
            datetime: lambda v: v.isoformat() if v else None
        }
        validate_assignment = True
        
    @validator('analysis_type')
    def validate_analysis_type(cls, v):
        """Validate analysis type."""
        allowed_types = [
            'call_tree', 'dependency_analysis', 'complexity_analysis', 
            'function_info', 'file_validation', 'call_chain',
            'syntax_analysis', 'semantic_analysis', 'performance_analysis'
        ]
        if v not in allowed_types:
            raise ValueError(f'analysis_type must be one of: {", ".join(allowed_types)}')
        return v


class AnalysisCreateSchema(BaseModel):
    """Schema for creating new analysis results."""
    
    call_tree_id: Optional[str] = None
    analysis_type: str = Field(description="Type of analysis performed")
    target_path: str = Field(description="File or directory path analyzed")
    language: Optional[str] = None
    results: Dict[str, Any] = Field(description="Analysis results data")
    success: bool = Field(default=True)
    error_message: Optional[str] = None
    processing_time_ms: Optional[float] = Field(None, ge=0)
    cache_key: Optional[str] = None
    file_hash: Optional[str] = None
    dependencies_hash: Optional[str] = None
    expires_at: Optional[datetime] = None
    metadata: Dict[str, Any] = Field(default_factory=dict)


class AnalysisUpdateSchema(BaseModel):
    """Schema for updating analysis results."""
    
    call_tree_id: Optional[str] = None
    results: Optional[Dict[str, Any]] = None
    success: Optional[bool] = None
    error_message: Optional[str] = None
    processing_time_ms: Optional[float] = Field(None, ge=0)
    cache_key: Optional[str] = None
    file_hash: Optional[str] = None
    dependencies_hash: Optional[str] = None
    expires_at: Optional[datetime] = None
    metadata: Optional[Dict[str, Any]] = None


class AnalysisSummarySchema(BaseModel):
    """Schema for analysis result summary data."""
    
    id: str
    analysis_type: str
    target_path: str
    language: Optional[str]
    success: bool
    processing_time_ms: Optional[float]
    created_at: datetime
    expires_at: Optional[datetime]
    
    class Config:
        """Pydantic configuration."""
        json_encoders = {
            datetime: lambda v: v.isoformat()
        }


class CallTreeAnalysisSchema(BaseModel):
    """Schema for call tree analysis results."""
    
    root_function: str = Field(description="Entry point function")
    total_nodes: int = Field(ge=0, description="Total number of nodes")
    max_depth: int = Field(ge=0, description="Maximum call depth")
    unique_files: int = Field(ge=0, description="Number of unique files involved")
    complexity_metrics: Dict[str, float] = Field(default_factory=dict, description="Complexity metrics")
    call_frequencies: Dict[str, int] = Field(default_factory=dict, description="Function call frequencies")
    critical_paths: List[List[str]] = Field(default_factory=list, description="Critical execution paths")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True


class DependencyAnalysisSchema(BaseModel):
    """Schema for dependency analysis results."""
    
    direct_dependencies: List[str] = Field(default_factory=list, description="Direct dependencies")
    indirect_dependencies: List[str] = Field(default_factory=list, description="Indirect dependencies")
    circular_dependencies: List[List[str]] = Field(default_factory=list, description="Circular dependency chains")
    dependency_graph: Dict[str, List[str]] = Field(default_factory=dict, description="Full dependency graph")
    dependency_count: int = Field(ge=0, description="Total number of dependencies")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True


class ComplexityAnalysisSchema(BaseModel):
    """Schema for complexity analysis results."""
    
    cyclomatic_complexity: Optional[float] = Field(None, ge=0, description="Cyclomatic complexity")
    cognitive_complexity: Optional[float] = Field(None, ge=0, description="Cognitive complexity")
    halstead_metrics: Dict[str, float] = Field(default_factory=dict, description="Halstead complexity metrics")
    lines_of_code: int = Field(ge=0, description="Lines of code")
    maintainability_index: Optional[float] = Field(None, ge=0, le=100, description="Maintainability index")
    complexity_hotspots: List[Dict[str, Any]] = Field(default_factory=list, description="High complexity areas")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True


class FunctionInfoSchema(BaseModel):
    """Schema for function information analysis results."""
    
    name: str = Field(description="Function name")
    signature: str = Field(description="Function signature")
    parameters: List[Dict[str, Any]] = Field(default_factory=list, description="Function parameters")
    return_type: Optional[str] = Field(None, description="Return type")
    documentation: Optional[str] = Field(None, description="Function documentation")
    decorators: List[str] = Field(default_factory=list, description="Function decorators")
    complexity_score: float = Field(ge=0, description="Function complexity score")
    line_count: int = Field(ge=0, description="Number of lines in function")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True


class CallChainAnalysisSchema(BaseModel):
    """Schema for call chain analysis results."""
    
    start_function: str = Field(description="Starting function")
    end_function: str = Field(description="Target function")
    path_found: bool = Field(description="Whether a path was found")
    call_path: Optional[List[str]] = Field(None, description="Call path if found")
    path_length: int = Field(ge=0, description="Length of call path")
    alternative_paths: List[List[str]] = Field(default_factory=list, description="Alternative call paths")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True


class BatchAnalysisSchema(BaseModel):
    """Schema for batch analysis operations."""
    
    analysis_requests: List[AnalysisCreateSchema] = Field(description="List of analysis requests")
    batch_id: Optional[str] = Field(None, description="Batch identifier")
    parallel: bool = Field(default=True, description="Whether to run analyses in parallel")
    max_concurrent: int = Field(default=10, ge=1, le=100, description="Maximum concurrent analyses")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True


class BatchAnalysisResultSchema(BaseModel):
    """Schema for batch analysis results."""
    
    batch_id: str = Field(description="Batch identifier")
    total_analyses: int = Field(ge=0, description="Total number of analyses")
    successful_analyses: int = Field(ge=0, description="Number of successful analyses")
    failed_analyses: int = Field(ge=0, description="Number of failed analyses")
    total_processing_time_ms: float = Field(ge=0, description="Total processing time")
    results: List[AnalysisResultSchema] = Field(description="Individual analysis results")
    errors: List[Dict[str, Any]] = Field(default_factory=list, description="Error details for failed analyses")
    
    class Config:
        """Pydantic configuration."""
        validate_assignment = True